home *** CD-ROM | disk | FTP | other *** search
/ Cream of the Crop 26 / Cream of the Crop 26.iso / program / p063b9s.zip / UNIT / SESSION.PAS < prev    next >
Pascal/Delphi Source File  |  1997-03-02  |  52KB  |  1,368 lines

  1. UNIT Session;
  2. {╔══════════════════════════════════════════════════════════════════════════╗}
  3. {║ Main loop in Portal of Power                  Last changed: 02.03.97  SA ║}
  4. {║                                                                          ║}
  5. {║                         (C) Copyright 1989-97 by                         ║}
  6. {║       Dan Wulff, Jens Sandalgaard, Steen Christensen & S¢ren Ager        ║}
  7. {║                                                                          ║}
  8. {║ This source may not be given to anybody, without the written permission  ║}
  9. {║ from The Portal Team.                                                    ║}
  10. {╚══════════════════════════════════════════════════════════════════════════╝}
  11. {$I POPDEFS.INC}
  12.  
  13. INTERFACE
  14.  
  15. USES Use32;
  16.  
  17. PROCEDURE PortalMain;
  18.  
  19. IMPLEMENTATION
  20.  
  21. USES Dos, OpDate, OpCrt, OpWindow, OpFrame, OpDos, OpEntry, OpEdit, OpCmd,
  22.      OpKey, OpRoot, OpString, OpInline, ApTimer,
  23.      PFix, Display, Com, Modem, OutMan, Event, Util, NlComp, OutUtil,
  24.      FileFwd, MailUtil, YooHoo2U, Nodelist, FileUtil, TextEdit, AreaMan,
  25.      DumbTerm, Config, NlMan, Init, Globals, FuncReq, List, PoPTypes,
  26.      Input, MTask, Keyboard, LogFile, ScrBlank, DosShell,
  27. {$IFNDEF Gamma}
  28.      OutMan2,
  29. {$ENDIF}
  30.      PopStatu, InterCom, OutInfo, OproUtil, StrUtil, Tick, Usage, UserEdit,
  31.      Resource ,MailScan, NewExp, NewImp, Fax, FuncSrvr, NetFile
  32. {$IFNDEF OS2}
  33.      , Macro
  34. {$ELSE}
  35.      , VpUtils
  36. {$ENDIF}
  37. {$IFDEF Repacker}
  38.      ,Repacker
  39. {$ENDIF}
  40. {$IFDEF Msgpack}
  41.      ,MsgPack
  42. {$ENDIF}
  43. {$IFDEF MSGOBJECT}
  44.      ,PoPEd
  45. {$ENDIF}
  46.      ;
  47.  
  48.   PROCEDURE SynchTime;
  49.   VAR
  50.     DT1, DT2 : DateTimeRec;
  51.     d, m, y : Integer;
  52.     h, min, sec : Byte;
  53.   BEGIN
  54.     DT1.D:=Today;
  55.     DT1.T:=CurrentTime;
  56.     IncDateTime(DT1, DT2, 0, SynchTimeDiff);
  57.     DateToDMY(DT2.D, d, m, y);
  58.     TimeToHMS(DT2.T, h, Min, Sec);
  59.     SetTime(Word(h), Word(min), Word(sec), 0); SetDate(y, m, d);
  60.     AddLog('+', 'Syncronizing time with remote');
  61.   END;
  62.  
  63.   PROCEDURE DoPortalTasks;
  64.   BEGIN
  65.     DropCarrier;
  66.     MakeModemBusy;
  67.     ParseRequest;
  68.     IF GotSomeFiles THEN
  69.     BEGIN
  70.       ProcessTicks;
  71.       ForwardFiles(False);
  72.     END;
  73. {$IFNDEF NoMailScanner}
  74.     IF GotSomeMail AND (CurrentEvent.typ AND etTossMail<>0) THEN
  75.       RunMailScanner(CurrentEvent.Typ AND (NOT etScanMail));
  76. {$ELSE}
  77.     ScanNetMail;
  78. {$ENDIF}
  79.     CompileNodeList(False);
  80.     UpdateNetMailFlag;
  81.   END;
  82.  
  83.   PROCEDURE CheckModemResponse(Forced: Boolean);
  84.   LABEL
  85.     NoBody, ItIsAlive, EMSIStart, KeepOnRocking;
  86.   VAR
  87.     StartTime,
  88.     EndTime      : DateTimeRec;
  89.     DTEBaud, w,
  90.     RealBaudRate : Word;
  91.     f            : TBufTextFile;
  92.     BBSNum, InByte,
  93.     i, ErrLvl    : Byte;
  94.     t,
  95.     WaitForUser  : EventTimer;
  96.     OkStr        : String[10];
  97.     CheckEMSI    : S127;
  98.     BatName      : S12;
  99.     ModemRes     : S80;
  100.     WaitWin      : WindowPtr;
  101.  
  102.     PROCEDURE SendIntro;
  103.     BEGIN
  104.       IF Cfg.UseEMSI THEN ComPort^.WriteStr(EMSIREQStr);
  105.       ComPort^.WriteStr(Char(Cr)+'* Network Address '+Address2Str(Cfg.Addresses[Cfg.MainAdrNum])+
  106.                         ' Using Portal of Power v'+Ver+Char(Cr));
  107.     END;
  108.  
  109.     FUNCTION ShowBanner: Boolean;
  110.     VAR
  111.       Banner  : TBufTextFile;
  112.       Ch, Ch1 : Char;
  113.       Done    : Boolean;
  114.       i       : Integer;
  115.     BEGIN
  116.       ComPort^.WriteByte(Byte(lf), True);
  117.       IF NOT Banner.Init(Cfg.Banner, SOpenRead+ShareDenyW, 512) THEN
  118.       BEGIN
  119.         AddLog('!','Can''t find banner file: '+cfg.banner);
  120.         ShowBanner:=False;
  121.       END ELSE
  122.       BEGIN
  123.         Done:=False; Ch1:=#0;
  124.         WHILE NOT Banner.EoF AND NOT Done DO
  125.         BEGIN
  126.           Banner.Read(Ch, 1);
  127.           ComPort^.WriteByte(Byte(Ch), True);
  128.           IF ComPort^.KeyPressed THEN
  129.           BEGIN
  130.             ComPort^.Peek(Byte(Ch1));
  131.             IF (Pos(UpCase(Ch1),OkStr)=0) THEN
  132.             BEGIN
  133.               Ch1:=Char(ComPort^.ReadByte);
  134.               CheckEMSI:=CheckEMSI+Ch1;
  135.               IF POS(EMSIINQStr,CheckEMSI)>0 THEN
  136.               BEGIN
  137.                 InByte:=0;
  138.                 Break;
  139.               END;
  140.             END ELSE
  141.               Done:=True;
  142.           END ELSE
  143.             Ch1:=#0;
  144.         END;
  145.         IF Done THEN
  146.         BEGIN
  147.           ComPort^.PurgeOut;
  148.           InByte:=Byte(Ch1);
  149.         END;
  150.         ShowBanner:=(Pos(UpCase(Ch1),OkStr)>2) and Done;
  151.         Banner.Done;
  152.       END;
  153.     END;
  154.  
  155.     PROCEDURE ShowFileToRemote(CONST FileName: PathStr);
  156.     VAR
  157.       f : TBufTextFile;
  158.       b : Byte;
  159.     BEGIN
  160.       IF f.Init(FileName, SOpenRead+ShareDenyW, 512) THEN
  161.       BEGIN
  162.         AddLog(':', 'Showing: '+FileName+' to remote');
  163.         WHILE NOT f.Eof AND ComPort^.Carrier DO
  164.         BEGIN
  165.           f.Read(b, 1); ComPort^.WriteByte(b, False);
  166.         END;
  167.         f.Done;
  168.         ComPort^.FlushTx;
  169.       END;
  170.     END;
  171.  
  172.     FUNCTION PrintableChars(CONST s: String): Boolean;
  173.     VAR
  174.       i : Byte;
  175.     BEGIN
  176.       PrintableChars:=True;
  177.       FOR i:=1 TO Length(s) DO
  178.         IF (s[i]<#32) OR (s[i]>#128) THEN PrintableChars:=False;
  179.     END;
  180.  
  181.  
  182.   BEGIN
  183.     WaitWin:=Nil;
  184.     ModemRes:='';
  185.     IF ComPort^.KeyPressed THEN
  186.       ModemRes:=ModemReadStr
  187.     ELSE
  188.       IF NOT Forced THEN Exit;
  189.     IF (ModemRes='RING') OR (Forced) THEN
  190.     BEGIN
  191.       IF Forced THEN AddLog(':', 'Forced modem answer') ELSE AddLog('#', ModemRes);
  192.       IF ((CurrentEvent.Typ AND etNoAnswer)=0) OR (Forced) THEN
  193.       BEGIN
  194.         IF Cfg.Modem.Answer<>'' THEN TranslateModemString(Cfg.Modem.Answer);
  195.       END ELSE
  196.         Goto NoBody;
  197.     END ELSE
  198.       Exit;
  199.     Tell(WaitWin, 'Waiting for modems to connect    ', 'Incomming call', (ScreenHeight DIV 2)-1, 2);
  200.     NewTimerSecs(t, Cfg.Modem.WaitTime);
  201.     REPEAT
  202.       GiveUpTime;
  203.       IF (GotESC) OR (TimerExpired(t)) THEN
  204.       BEGIN
  205.         IF TimerExpired(t) THEN AddLog('#', 'Timeout waiting for connect');
  206.         GOTO NoBody;
  207.       END;
  208.       IF ComPort^.KeyPressed THEN ModemRes:=ModemReadStr ELSE ModemRes:='';
  209.       IF (ModemRes<>'') AND (Copy(ModemRes, 1, 2)<>'AT') AND PrintableChars(ModemRes) THEN
  210.       BEGIN
  211.         AddLog('#', ModemRes);
  212.         ErrLvl:=CheckConnectExit(ModemRes);
  213.         IF ErrLvl<>0 THEN
  214.         BEGIN
  215.           FillChar(Call, SizeOf(Call), 0);
  216.           Call.Zone:=-1;
  217.           AddToCallList(1, Call, ModemRes);
  218.           KillWindow(WaitWin);
  219.           SpawnWithErrorLevel(ErrLvl, 'Exit on CONNECT string', False);
  220.         END;
  221.         IF (ModemRes='NO CARRIER') {OR (ModemRes='RING')} THEN GOTO NoBody;
  222.       END;
  223.       WaitWin^.wFastText(LongIntForm('###',RemainingTimeInSecs(t)),1,32);
  224.     UNTIL (Copy(ModemRes,1,7)='CONNECT') OR ((Pos('+FCO', ModemRes)>0) AND (Cfg.Modem.InternalFax));
  225.     KillWindow(WaitWin); WaitWin:=Nil;
  226.     IF (Pos('+FCO', ModemRes)>0) AND (Cfg.Modem.InternalFax) THEN
  227.     BEGIN
  228.       GetFax;
  229.       GOTO NoBody;
  230.     END;
  231.     RealBaudRate:=GetRealBaudRate(ModemRes);
  232.     IF IsLockedBaud(ModemRes) THEN
  233.     BEGIN
  234.       ComPort^.SetBaudRate(Cfg.Modem.BaudRate);
  235.       ComPort^.SetCurrentBaud(RealBaudRate);
  236.       AddLog(' ','DTE Speed: '+Long2Str(Cfg.Modem.BaudRate)+', Line speed: '+Long2Str(Realbaudrate));
  237.     END ELSE
  238.     BEGIN
  239.       ComPort^.SetBaudRate(RealBaudRate);
  240.     END;
  241.     ComPort^.PurgeIn;
  242.     FullDuplex:=CheckBiOverride(ModemRes);
  243.     WaitForSlowModem;
  244.     UpdateStatusWindow;
  245.     MNPFilter;
  246.     NewTimerSecs(WaitForUser, 3);
  247.     InByte:=0;
  248.     CheckEMSI:='';
  249.     CalculateEventTimes(True);
  250.     WHILE (ComPort^.Carrier) AND (NOT TimerExpired(WaitForUser)) AND NOT (InByte IN [Escape,Lf,Cr,32,YooHoo,TSync]) DO
  251.       IF ComPort^.KeyPressed THEN
  252.       BEGIN
  253.         InByte:=ComPort^.ReadByte;
  254.         IF (InByte>31) AND (InByte<128) THEN
  255.         BEGIN
  256.           CheckEMSI:=CheckEMSI+Char(InByte);
  257.           IF Length(CheckEMSI)>100 THEN Delete(CheckEMSI,1,50);
  258.           IF (Cfg.UseEMSI) AND (POS(EMSIINQStr,CheckEMSI)<>0) THEN
  259.           BEGIN
  260.             InByte:=0;
  261.             GOTO EMSIStart;
  262.           END;
  263.         END;
  264.       END ELSE
  265.         GiveUpTime;
  266.     IF NOT ComPort^.Carrier THEN
  267.     BEGIN
  268.       AddLog(':', 'Caller disappeared?');
  269.       GOTO NoBody;
  270.     END;
  271.     IF (InByte<>YooHoo) AND (InByte<>TSync) THEN
  272.     BEGIN
  273.       OkStr:=Char(TSync)+Char(YooHoo);
  274.       FOR i:=1 TO 5 DO
  275.         IF (Cfg.BBS.Multi[i].Key>' ') AND (Cfg.BBS.Multi[i].BatName<>'') THEN
  276.           OkStr:=OkStr+Cfg.BBS.Multi[i].Key;
  277.       IF (Cfg.BBS.Multi[1].Key<=' ') OR (Cfg.BBS.Multi[i].BatName='') THEN OkStr:=OkStr+Char(Escape);
  278.       SendIntro;
  279.       IF cfg.banner<>'' THEN
  280.         IF ShowBanner THEN GOTO ItIsAlive;
  281.       IF POS(EMSIINQStr,CheckEMSI)>0 THEN GOTO EmsiStart;
  282.       IF (CurrentEvent.Typ AND etUsers)=0 THEN
  283.         ComPort^.WriteStr(Char(lf)+Cfg.DoingMailText+Char(cr)+Char(lf))
  284.       ELSE
  285.         IF Cfg.BBS.Multi[1].Key<=' ' THEN ComPort^.WriteStr(Char(lf)+Cfg.PressESCText+Char(cr)+Char(lf));
  286.       NewTimerSecs(WaitForUser, 30);
  287.       REPEAT
  288.         IF ComPort^.KeyPressed THEN
  289.         BEGIN
  290.           InByte:=ComPort^.ReadByte;
  291.           IF (InByte>31) AND (InByte<127) THEN
  292.           BEGIN
  293.             CheckEMSI:=CheckEMSI+Char(InByte);
  294.             IF (Cfg.UseEMSI) AND (POS(EMSIINQStr,CheckEMSI)<>0) THEN
  295.             BEGIN
  296.               InByte:=0;
  297.               GOTO EMSIStart;
  298.             END;
  299.             IF Length(CheckEMSI)>100 THEN Delete(CheckEMSI,1,50);
  300.           END;
  301.         END ELSE
  302.         BEGIN
  303.           GiveUpTime;
  304.           InByte:=0;
  305.         END;
  306.         CASE UpCase(Char(InByte)) OF
  307.           Char(Lf),
  308.           Char(Cr),
  309.           Char(32) : SendIntro;
  310.           ELSE IF POS(UpCase(Char(InByte)),OKStr)>2 THEN GOTO ItIsAlive;
  311.         END;
  312.       UNTIL (TimerExpired(WaitForUser)) OR (InByte IN [Escape,YooHoo,TSync]) OR (NOT ComPort^.Carrier);
  313.       IF NOT ComPort^.Carrier THEN
  314.       BEGIN
  315.         AddLog(':', 'Caller disappeared?');
  316.         GOTO NoBody;
  317.       END;
  318.     END;
  319.     IF InByte IN [YooHoo,TSync] THEN
  320.     BEGIN
  321. EMSIStart:
  322.       StopClock;
  323.       MyWin(IntroWin,1,ScreenHeight-1,80,ScreenHeight,2,'',False);
  324.       Inc(StatRec^.DayStat[0].MailSessions);
  325.       UpdateConnectStat(CSMail, CSIn, RealBaudRate, ModemRes);
  326.       FSent:=0; FReceived:=0;
  327.       StartTime.T:=CurrentTime; StartTime.D:=Today;
  328.       SynchTimeDiff:=0;
  329.       ReceiveMailSession(InByte);
  330.       EndTime.T:=CurrentTime;
  331.       EndTime.D:=Today;
  332.       UpdateUsageStat(StartTime,EndTime,USMailIn);
  333.       LogLinkStat;
  334.       IF Abs(SynchTimeDiff)>10 THEN SynchTime;
  335.       RemoveUnDialable(Call);
  336.       IF FReceived<>0 THEN DoPortalTasks;
  337.       IF (CurrentEvent.MailExit>0) AND GotSomeMail THEN
  338.       BEGIN
  339.         SetInterCom(ICUnpackMail,Call,False);
  340.         IF Cfg.TaskType=2 THEN
  341.           RequestFunction(fsExit+(256*CurrentEvent.MailExit))
  342.         ELSE
  343.           SpawnWithErrorlevel(CurrentEvent.MailExit, 'Exit after mail', True);
  344.       END
  345.       ELSE
  346.         IF (CurrentEvent.FilesExit>0) AND GotSomeFiles THEN
  347.         BEGIN
  348.           SetInterCom(ICUnpackMail,Call,False);
  349.           IF Cfg.TaskType=2 THEN
  350.             RequestFunction(fsExit+(256*CurrentEvent.FilesExit))
  351.           ELSE
  352.             SpawnWithErrorlevel(CurrentEvent.FilesExit, 'Exit after files', True);
  353.         END
  354.         ELSE
  355.           IF CurrentEvent.PollExit>0 THEN
  356.           BEGIN
  357.             IF Cfg.TaskType=2 THEN
  358.               RequestFunction(fsExit+(256*CurrentEvent.PollExit))
  359.             ELSE
  360.               SpawnWithErrorlevel(CurrentEvent.PollExit, 'Exit after poll', True);
  361.           END;
  362.       NewTimer(OutBoundReRead, 0);
  363.     END ELSE
  364.     BEGIN
  365. ItIsAlive:
  366.       UpdateConnectStat(CSUser, CSIn, RealBaudRate, ModemRes);
  367.       IF (CurrentEvent.Typ AND etUsers)=0 THEN
  368.       BEGIN
  369.         AddLog('#', 'Hanging up on user in mail session');
  370.         ModemHangUp;
  371.         InitModemForEvent;
  372.         GOTO NoBody;
  373.       END ELSE
  374.       BEGIN
  375.         IF RealBaudRate<Cfg.BBS.MinBaud THEN
  376.         BEGIN
  377.           AddLog('*','Ax''ing too slow caller');
  378.           IF ExistFile(Cfg.BBS.MinBaudFile) THEN ShowFileToRemote(Cfg.BBS.MinBaudFile);
  379.           Pause(1000);
  380.           GOTO NoBody;
  381.         END;
  382.         BBSNum:=0;
  383.         IF Cfg.BBS.Multi[1].Key>' ' THEN
  384.         BEGIN
  385.           REPEAT
  386.             IF POS(UpCase(Char(InByte)),Okstr)<3 THEN
  387.             BEGIN
  388.               WHILE Not ComPort^.KeyPressed AND  (NOT TimerExpired(WaitForUser)) DO
  389.                 GiveUpTime;
  390.               IF ComPort^.KeyPressed AND ComPort^.Carrier THEN InByte:=ComPort^.ReadByte;
  391.             END;
  392.             BBSNum:=1;
  393.             IF TimerExpired(WaitForUser) THEN
  394.             BEGIN
  395.               InByte:=Byte(Cfg.BBS.Multi[1].Key);
  396.               GOTO KeepOnRocking;
  397.             END;
  398.             WHILE (BBSNum<5) And (Cfg.BBS.Multi[BBSNum].Key<>UpCase(Char(InByte))) DO
  399.               Inc(BBSNum);
  400.           UNTIL (Cfg.BBS.Multi[BBSNum].Key=UpCase(Char(InByte))) OR Not ComPort^.Carrier;
  401.         END;
  402. KeepOnRocking:
  403.         IF NOT ComPort^.Carrier THEN GOTO NoBody;
  404.         Inc(StatRec^.DayStat[0].BBSSessions);
  405.         ComPort^.WriteStr(Char(cr)+Char(lf)+Cfg.EnterBBSText+Char(cr)+Char(lf));
  406.         AddLog('#','Entering BBS-'+Long2Str(RealBaudRate));
  407.         f.Init(MakeTaskFileName('BBSBATCH.BAT'), SCreate, 128);
  408.         IF InitStatus<>0 THEN AddLog('!', 'Error: '+Long2Str(InitStatus)+' when creating: '+MakeTaskFileName('BBSBATCH.BAT'));
  409.         IF (BBSNum>0) AND (Cfg.BBS.Multi[BBSNum].BatName<>'') THEN
  410.           BatName:=Cfg.BBS.Multi[BBSNum].BatName
  411.         ELSE
  412.           BatName:='SPAWNBBS';
  413.         IF IsLockedBaud(ModemRes) THEN DTEBaud:=Cfg.Modem.BaudRate ELSE DTEBaud:=RealBaudRate;
  414.         f.WriteLn(BatName+' '+Long2Str(RealBaudRate)+' '+
  415.                   Long2Str(Cfg.Modem.Commport)+' '+
  416.                   Long2Str(TimeToNextForcedEvent DIV 60)+' '+
  417.                   Long2Str(Cfg.TaskNumber)+' '+
  418.                   Long2Str(DTEBaud)+' '+GetExtraInfo(ModemRes));
  419.         f.Done;
  420.         IF SetInterCom(ICUserInBBS,Call,False) THEN
  421.         BEGIN
  422.           w:=Cfg.BBS.UserErrorLevel;
  423.           IF w=0 THEN w:=RealBaudRate DIV 100;
  424.           SpawnWithErrorlevel(w, 'Spawning to BBS', False);
  425.         END;
  426.       END;
  427.     END;
  428. NoBody:
  429.     SetInterCom(ICIdle,Call,False);
  430.     IF WaitWin<>Nil THEN KillWindow(WaitWin);
  431.     DropCarrier;
  432.     InitModemForEvent;
  433.     StartClock;
  434.   END;
  435.  
  436.   FUNCTION FindSpecialModemDial: S40;
  437.   VAR
  438.     s : S40;
  439.     i : Byte;
  440.   BEGIN
  441.     s:='';
  442.     FOR i:=0 TO 7 DO
  443.       IF (1 SHL Cfg.Modem.ModemType[i].Bit) AND NodeListEntry.ModemType<>0 THEN
  444.       BEGIN
  445.         s:=Cfg.Modem.ModemType[i].Dial;
  446.         Break;
  447.       END;
  448.     IF s='' THEN s:=Cfg.Modem.Dial;
  449.     FindSpecialModemDial:=s;
  450.   END;
  451.  
  452.   FUNCTION NoConnect(CONST s: STRING): Boolean;
  453.   BEGIN
  454.     NoConnect:=((s='BUSY') Or (s='VOICE') Or (Copy(s,1,2)='NO'));
  455.   END;
  456.  
  457.   PROCEDURE Dial(Manuel: Boolean);
  458.   LABEL
  459.     Fubar;
  460.   VAR
  461.     NumRinging   : Byte;
  462.     dt1,dt2      : DateTimeRec;
  463.     i,
  464.     Baud         : Word;
  465.     Temp         : windowptr;
  466.     RealBaudRate : Word;
  467.     Escaped      : Boolean;
  468.     ModemRes     : S80;
  469.     s            : STRING;
  470.     BusyFile     : File;
  471.     Seconds,
  472.     t            : EventTimer;
  473.  
  474.     PROCEDURE ShowCallCost;
  475.     VAR
  476.       NodeCost : LongInt;
  477.       Days     : Word;
  478.       Seconds  : LongInt;
  479.     BEGIN
  480.       dt2.t:=CurrentTime; dt2.d:=Today;
  481.       UpdateUsageStat(dt1,dt2,USMailOut);
  482.       Datetimediff(dt1,dt2,days,seconds);
  483.       IF Seconds<10 THEN Seconds:=10;
  484.       NodeCost:=(((days*86400)+seconds+59) DIV 60)*NodelistEntry.RealCost;
  485.       StatRec^.DayStat[0].Cost:=StatRec^.DayStat[0].Cost+NodeCost;
  486.       AddLog(':', 'Connected to: '+Address2Str(Call)+' for: '+TimeToTimeString('hh:mm:ss', (days*86400)+Seconds)+
  487.                   ' cost: '+Long2Str(NodeCost));
  488.     END;
  489.  
  490.     PROCEDURE UpdateCallsOutStat(AStart, AFinish: DateTimeRec;
  491.                                  AnAddress: TFidoAddress;
  492.                                  AfilesIn, AFilesOut: Word;
  493.                                  AConnectSpeed: LongInt);
  494.     VAR
  495.       CallStat : TCallStat;
  496.       CallStatFile : TNetFile;
  497.       FName    : PathStr;
  498.       NodeCost : LongInt;
  499.       Days     : Word;
  500.       Seconds      : LongInt;
  501.     BEGIN
  502.       FillChar(CallStat, SizeOf(CallStat), 0);
  503.       FName:=StartPath+MakeTaskFileName('PORTAL.SCO');
  504.       IF CallStatFile.Open(FName, SizeOf(CallStat), True) THEN
  505.       BEGIN
  506.         DateTimeDiff(dt1,dt2,Days,Seconds);
  507.         IF Seconds<10 THEN Seconds:=10;
  508.         NodeCost:=(((Days*86400)+Seconds+59) DIV 60)*NodelistEntry.RealCost;
  509.         WITH CallStat DO
  510.         BEGIN
  511.           Start        := AStart;
  512.           Finish       := AFinish;
  513.           Address      := AnAddress;
  514.           MailerType   := RemHello.ProductCode;
  515.           SystemName   := AsciiZ2Str(RemHello.SystemName,60);
  516.           SysOpName    := AsciiZ2Str(RemHello.SysOp,20);
  517.           FilesIn      := AFilesIn;
  518.           FilesOut     := AFilesOut;
  519.           Cost         := (((Days*86400)+Seconds+59) DIV 60)*NodelistEntry.RealCost;
  520.           ConnectSpeed := AConnectSpeed;
  521.         END;
  522.         CallStatFile.PutRec(CallStat, CallStatFile.FileSize);
  523.         CallStatFile.Close;
  524.       END ELSE
  525.         AddLog('!', 'Error opening/creating: '+FName);
  526.     END;
  527.  
  528.     FUNCTION Best(w1, w2: Word): Word;
  529.     BEGIN
  530.       Best:=w2;
  531.       IF w1<>0 THEN Best:=w1;
  532.     END;
  533.  
  534.   BEGIN
  535.     RemapAddress(Call);
  536.     IF (NodelistEntry.PhoneNumber='') And (NodesRec.Phone='') THEN
  537.     BEGIN
  538.       IF Manuel THEN
  539.       BEGIN
  540.         s:='';
  541.         IF InputString(10,8,20,20,2,'Node does NOT exist','Phone : ',s) THEN
  542.         BEGIN
  543.           WITH NodeListEntry DO
  544.           BEGIN
  545.             Adr.Zone:=Call.zone;
  546.             Adr.Net:=Call.net;
  547.             Adr.Node:=Call.node;
  548.             Systemname:='Unknown node!!!';
  549.             phonenumber:=s;
  550.           END;
  551.         END ELSE
  552.           Exit;
  553.       END ELSE
  554.         Exit;
  555.     END ELSE
  556.       IF NodesRec.Phone<>'' THEN NodelistEntry.PhoneNumber:=NodesRec.Phone;
  557.     IF Manuel AND ((NodelistEntry.Flags AND nlf_CrashMail)=0) AND
  558.        NOT Confirm(Address2Str(Call)+' is not a CM system - call anyway?', 'Y', 9) THEN Exit;
  559.     Data.NextTime.StartTics:=0;
  560.     AddLog(':','Polling: '+Address2Str(Call)+', '+NodelistEntry.SystemName);
  561.     IF ComPort^.KeyPressed AND (ModemReadStr='RING') THEN
  562.     BEGIN
  563.       IF (CurrentEvent.Typ AND etNoAnswer)=0 THEN
  564.       BEGIN
  565.         AddLog(':','Incoming call detected - Answering modem');
  566.         NewTimerSecs(t, 5);
  567.         WHILE Not ComPort^.KeyPressed AND Not TimerExpired(t) DO  { Wait for another ring }
  568.           GiveUpTime;
  569.         CheckModemResponse(False);
  570.       END ELSE
  571.         AddLog(':','Incoming call detected - dial aborted');
  572.       Exit;
  573.     END;
  574.     IF NOT MarkNodeBusy(BusyFile, Call) THEN
  575.     BEGIN
  576.       AddLog(':',Address2Str(Call)+' is marked busy - skipping');
  577.       Exit;
  578.     END ELSE
  579.       UnMarkNodeBusy(BusyFile);
  580.     IF NOT SetInterCom(ICPolling,Call,False) THEN Exit;
  581.     ComPort^.WriteByte(Cr, True);
  582.     mywin(Temp,15,9,65,18,2,'Dialing',True);
  583.     WITH NodelistEntry, Temp^,Cfg.Color[2] DO
  584.     BEGIN
  585.       wFastText('Address    :',2,2);
  586.       wfastwrite(Address2Str(Call),2,15,HighLightColor);
  587.       wFastText('System     :',3,2);
  588.       wfastwrite(SystemName,3,15,HighLightColor);
  589.       wFastText('Sysop      :',4,2);
  590.       wfastwrite(SysopName,4,15,HighLightColor);
  591.  
  592.       wFastText('Misc.Info  :',5,2);
  593.       wfastwrite(MiscInfo,5,15,HighLightColor);
  594.       IF cfg.Modem.BaudRate<BaudRate THEN Baud:=cfg.Modem.BaudRate ELSE Baud:=BaudRate;
  595.       s:='';
  596.       FOR i:=0 TO 7 DO
  597.         IF (1 SHL Cfg.Modem.ModemType[i].Bit) AND ModemType<>0 THEN
  598.           s:=s+', '+Cfg.NlCompiler.MTypeStr[Cfg.Modem.ModemType[i].Bit];
  599.       wFastText('Baud (Max) :',6,2);
  600.       wfastwrite(Long2Str(Baud)+' ('+Long2Str(BaudRate)+s+')',6,15,HighLightColor);
  601.       wFastText('Cost/Min   :',7,2);
  602.       wfastwrite(Long2Str(RealCost),7,15,HighLightColor);
  603.     END;
  604.     Inc(StatRec^.DayStat[0].CallsOut);
  605.     IF FoundInNodes And (NodesRec.SpecialDials[CurrentEvent.SpecDial]<>'') THEN
  606.       s:=NodesRec.SpecialDials[CurrentEvent.SpecDial] ELSE s:=FindSpecialModemDial;
  607.  
  608.     IF IsOurAddress(Call) THEN Nodelistentry.PhoneNumber:=PhoneTranslation(Nodelistentry.PhoneNumber);
  609.     TranslateModemString(s+nodelistentry.PhoneNumber+'|');
  610.     AddLog(':','Dialing: '+s+nodelistentry.PhoneNumber);
  611.     NewTimerSecs(Seconds, Cfg.Modem.WaitTime);
  612.     Escaped:=False; NumRinging:=0;
  613.     REPEAT
  614.       IF ComPort^.KeyPressed THEN
  615.       BEGIN
  616.         ModemRes:=ModemReadStr;
  617.         IF (Copy(ModemRes,1,2)<>'AT') AND (ModemRes<>'') THEN
  618.         BEGIN
  619.           AddLog('#',ModemRes);
  620.           IF Copy(ModemRes, 1, 7)='RINGING' THEN Inc(NumRinging);
  621.           IF (Cfg.MaxRinging>0) AND (NumRinging>=Cfg.MaxRinging) THEN
  622.           BEGIN
  623.             AddLog('!', 'I hear too much ringing in my ears....');
  624.             UpdateUnDialable(Call, 1, 0);
  625.             Escaped:=True;
  626.           END;
  627.         END;
  628.       END ELSE
  629.       BEGIN
  630.         ModemRes:='';
  631.         GiveUpTime;
  632.       END;
  633.       IF GotESC THEN Escaped:=True;
  634.     UNTIL (NoConnect(ModemRes)) OR (Copy(modemres,1,7)='CONNECT') OR (Escaped) OR (TimerExpired(Seconds));
  635.     KillWindow(Temp);
  636.     IF Escaped THEN
  637.     BEGIN
  638.       AddLog(':','Poll aborted, hanging up');
  639.       ModemHangUp;
  640.       InitModemForEvent;
  641.       SetInterCom(ICIdle,Call,False);
  642.       NewTimerSecs(Data.NextTime, CalculateNextTime);
  643.       Exit;
  644.     END;
  645.  
  646.     dt1.d:=Today; dt1.t:=CurrentTime;
  647.     IF ((CurrentEvent.Typ AND etNoAnswer)=0) AND
  648.        (Copy(ModemRes, 1, 7)='NO DIAL') AND (Cfg.Modem.Answer<>'') THEN
  649.     BEGIN
  650.       SetInterCom(ICIdle,Call,False);
  651.       CheckModemResponse(True);
  652.       NewTimerSecs(Data.NextTime, CalculateNextTime);
  653.       Exit;
  654.     END;
  655.  
  656.     WaitForSlowModem;
  657.     IF (Copy(ModemRes,1,7)='CONNECT') AND (ComPort^.Carrier) THEN
  658.     BEGIN
  659.       StopClock;
  660.       RealBaudRate:=GetRealBaudRate(ModemRes);
  661.       UpdateConnectStat(CSMail, CSOut, RealBaudRate, ModemRes);
  662.       IF (((NodesRec.CheckConnect IN [#0,' ']) And (Cfg.ConnectFastest)) Or (NodesRec.CheckConnect='Y')) And
  663.          (RealBaudRate<Best(NodesRec.MinConnectBaud, Baud)) THEN
  664.       BEGIN
  665.         AddLog('!','Too slow connection - Poll aborted');
  666.         ShowCallCost;
  667.         GOTO Fubar;
  668.       END;
  669.       IF IsLockedBaud(ModemRes) THEN
  670.       BEGIN
  671.         ComPort^.SetBaudRate(Cfg.Modem.BaudRate);
  672.         ComPort^.SetCurrentBaud(RealBaudRate);
  673.         AddLog(' ','DTE Speed: '+Long2Str(Cfg.Modem.BaudRate)+', Line speed: '+Long2Str(Realbaudrate));
  674.       END ELSE
  675.       BEGIN
  676.         ComPort^.SetBaudRate(RealBaudRate);
  677.       END;
  678.       FullDuplex:=CheckBiOverride(ModemRes);
  679.       UpdateStatusWindow;
  680.       FSent:=0; FReceived:=0;
  681.       IF NOT SetInterCom(ICConnect,Call,False) THEN
  682.       BEGIN
  683.         ShowCallCost;
  684.         GOTO Fubar;
  685.       END;
  686.       MNPFilter;
  687.       SynchTimeDiff:=0;
  688.       IF StartMailSession THEN
  689.       BEGIN
  690.         ShowCallCost;
  691. {$IFDEF Alpha}
  692.         UpdateCallsOutStat(dt1,dt2,call,FReceived,FSent,RealBaudRate);
  693. {$ENDIF}
  694.         IF Abs(SynchTimeDiff)>10 THEN SynchTime;
  695.         LogLinkStat;
  696.         RemoveUnDialable(Call);
  697.         IF FReceived<>0 THEN DoPortalTasks;
  698.         IF (CurrentEvent.MailExit<>0) AND GotSomeMail AND SetInterCom(ICUnpackMail,Call,False) THEN
  699.         BEGIN
  700.           IF Cfg.TaskType=2 THEN
  701.             RequestFunction(fsExit+(256*CurrentEvent.MailExit))
  702.           ELSE
  703.             SpawnWithErrorlevel(CurrentEvent.MailExit, 'Exit after mail', True);
  704.         END
  705.         ELSE
  706.           IF (CurrentEvent.FilesExit>0) AND GotSomeFiles AND SetInterCom(ICUnpackMail,Call,False) THEN
  707.           BEGIN
  708.             IF Cfg.TaskType=2 THEN
  709.               RequestFunction(fsExit+(256*CurrentEvent.FilesExit))
  710.             ELSE
  711.               SpawnWithErrorlevel(CurrentEvent.FilesExit,'Exit after files', True);
  712.           END;
  713.       END ELSE
  714.       BEGIN
  715.         UpdateUnDialable(Call, 0, 1);
  716.         ShowCallCost;
  717.       END;
  718.       NewTimer(OutBoundReRead, 0);
  719.     END ELSE
  720.     BEGIN
  721.       IF ModemRes<>'BUSY' THEN ShowCallCost;
  722.       IF TimerExpired(Seconds) THEN AddLog('#', 'Other end did not answer');
  723.       UpdateUnDialable(Call, 1, 0);
  724.     END;
  725.     AddLog(':', 'Poll completed');
  726. FuBar:
  727.     SetInterCom(ICIdle, Call, False);
  728.     ModemHangUp;
  729.     InitModemForEvent;
  730.     UpdateStatusWindow;
  731.     StartClock;
  732.     NewTimerSecs(Data.NextTime, CalculateNextTime);
  733.   END;
  734.  
  735.   PROCEDURE PollNode;
  736.   VAR
  737.     TmpPtr : POutList;
  738.   BEGIN
  739.     WITH Data DO
  740.     BEGIN
  741.       IF Poll.Zone+Poll.Net+Poll.Node+Poll.Point=0 THEN
  742.       BEGIN
  743.         Poll:=cfg.Addresses[Cfg.MainAdrNum];
  744.         Poll.Node:=0;
  745.         Poll.Point:=0;
  746.       END;
  747.       IF GetAddress(11,2,Poll,1500) THEN
  748.       BEGIN
  749.         Call:=Poll;
  750.         TmpPtr:=POutList(OutList^.Head);
  751.         WHILE (TmpPtr<>Nil) And Not CmpAdr(Poll,TmpPtr^.Address) DO
  752.           TmpPtr:=POutList(OutList^.Next(TmpPtr));
  753.         IF TmpPtr<>Nil THEN
  754.         BEGIN
  755.           CLOutListPtr:=TmpPtr; FLOutListPtr:=TmpPtr;
  756.           UpdateOutboundWindow;
  757.         END;
  758.         Dial(True);
  759.       END;
  760.     END;
  761.   END;
  762.  
  763.   PROCEDURE PortalMain;
  764.   VAR
  765.     MSFlags        : LONGINT;
  766.     TmpWin         : WindowPtr;
  767.     OldOutPtr,
  768.     SaveOutPtr     : POutList;
  769.     MustReRead,
  770.     ResetTimers,
  771.     PortalFinished,
  772.     JustScrolled   : Boolean;
  773.     TmpCh          : Char;
  774.     i,Tmp          : Byte;
  775.     ii             : Integer;
  776.     InKey          : Word;
  777.     Fs, LastChoice : LongInt;
  778.     s              : String;
  779.     fp             : LongInt;
  780.     SemaforeTimer,
  781.     ReturnFromLog  : EventTimer;
  782.  
  783.     PROCEDURE CheckSemaforeFiles;
  784.     VAR
  785.       ELevel : Byte;
  786.       Ok : Integer;
  787.       Sr : SearchRec;
  788.       Adr: TFidoAddress;
  789.     BEGIN
  790.       s:=StartPath+MakeTaskFileName('PORTAL.E*');
  791.       FindFirst(s, AnyFile, sr);
  792.       IF DOSError=0 THEN
  793.       BEGIN
  794.         Val('$'+Copy(sr.name,Length(Sr.Name)-1,2), ELevel, Ok);
  795.         IF Ok=0 THEN
  796.         BEGIN
  797.           Adr.Zone:=ELevel;
  798.           IF SetInterCom(ICSemExit, Adr, False) THEN
  799.           BEGIN
  800.             FindClose(sr);
  801.             DeleteFile(StartPath+Sr.Name);
  802.             SpawnWithErrorlevel(ELevel,'Semafore exit', True);
  803.           END;
  804.         END;
  805.       END;
  806.       FindClose(sr);
  807.       NewTimerSecs(SemaforeTimer, 60);
  808.     END;
  809.  
  810.     FUNCTION StillHaveMail(CONST Adr: TFidoAddress): Boolean;
  811.     VAR
  812.       sr        : SearchRec;
  813.       s         : PathStr;
  814.       FoundMail : Boolean;
  815.     BEGIN
  816.       s:=HoldFileName(Adr, False)+'?LO';
  817.       FindFirst(s, Archive, Sr);
  818.       WHILE (DOSError=0) AND (Sr.Name[10]='H') DO
  819.         FindNext(Sr);
  820.       FoundMail:=(DOSError=0);
  821.       FindClose(Sr);
  822.       IF NOT FoundMail THEN
  823.       BEGIN
  824.         s:=HoldFileName(Adr, False)+'?UT';
  825.         FindFirst(s, Archive, Sr);
  826.         WHILE (DOSError=0) AND (Sr.Name[10]='H') DO
  827.           FindNext(Sr);
  828.         FoundMail:=(DOSError=0);
  829.         FindClose(Sr);
  830.       END;
  831.       StillHaveMail:=FoundMail;
  832.     END;
  833.  
  834.   BEGIN
  835.     LastChoice:=0;
  836.     PortalFinished:=False;
  837. {$IFNDEF NOMAILSCANNER}
  838.     MSFlags:=0;
  839.     IF CmdLineFlags AND clMailScan<>0 THEN MSFlags:=MSFlags OR etScanMail;
  840.     IF CmdLineFlags AND clMailToss<>0 THEN MSFlags:=MSFlags OR etTossMail;
  841.     IF CmdLineFlags AND clMailPack<>0 THEN MSFlags:=MSFlags OR etPackMail;
  842.     IF MSFlags<>0 THEN RunMailScanner(MSFlags);
  843. {$ENDIF}
  844.     NewTimerSecs(ScreenBlank, Cfg.Screen.BlankTime);
  845.     NewTimerSecs(ModemReInit, Cfg.Modem.Reinit);
  846.     NewTimerSecs(SemaforeTimer, 15);
  847.     NewTimerSecs(ReturnFromLog, 30);
  848.     REPEAT
  849.       Topic:=10;
  850.       HiddenCursor;
  851.       JustScrolled:=False;
  852.       IF Cfg.TaskType=1 THEN FunctionServer;
  853.       IF PoPKeyPressed THEN
  854.       BEGIN
  855.         InKey:=PopReadKeyWord;
  856.         StopClock; ResetTimers:=True;
  857.         CASE Char(Lo(InKey)) OF
  858.           '+',
  859.           '-': IF OutList^.Size>0 THEN
  860.                BEGIN
  861.                  IF Char(Lo(InKey))='-' THEN
  862.                    GlueNode(CLOutListPtr^.Address)
  863.                  ELSE
  864.                    UnGlueNode(CLOutListPtr^.Address);
  865.                  CLOutListPtr^.Glued:=(Char(Lo(InKey))='-');
  866.                  UpdateOutboundWindow;
  867.                END;
  868.           #13: IF (CmdLineFlags AND clNoModem=0) AND (OutList^.Size>0) And (CLOutListPtr^.Known) AND (Not InLogWin) THEN
  869.                BEGIN
  870.                  WITH CLOutListPtr^ DO
  871.                    Call:=Address;
  872.                  Dial(True);
  873.                END;
  874.           ELSE BEGIN
  875.                  CASE InKey OF
  876.                    AltA : IF Cfg.BBS.BBSType<>btNone THEN
  877.                           BEGIN
  878.                             MakeModemBusy;
  879.                             AreaManager;
  880.                           END;
  881.                    AltB : BEGIN
  882.                             NewTimer(ScreenBlank, 0);
  883.                             ResetTimers:=False;
  884.                           END;
  885.                    AltC : IF CmdLineFlags AND clNoModem=0 THEN
  886.                           BEGIN
  887.                             AddLog(':','Immediate call requested');
  888.                             NewTimer(Data.NextTime, 0);
  889.                             ResetTimers:=False;
  890.                           END;
  891.                    AltD : TerminalMode;
  892.                    AltE : IF (Cfg.Editor<>'') THEN
  893.                           BEGIN
  894.                             IF (SetInterCom(ICMsgEdit,Call,False)) THEN
  895.                             BEGIN
  896.                               MakeModemBusy;
  897.                               AddLog('!','Invoking message reader');
  898.                               ii:=ShellToDos(GetEnv('COMSPEC'),'/C '+cfg.editor,true);
  899.                               IF ii=0 THEN
  900.                               BEGIN
  901.                                 AddLog(':','Returning from message reader');
  902.                                 IF NOT ComPort^.KeyPressed THEN
  903.                                 BEGIN
  904.                                   UpdateNetMailFlag;
  905.                                   NewTimerSecs(OutboundReRead, 1) ;
  906.                                 END;
  907.                               END ELSE
  908.                                 AddLog('!', 'Error '+Long2Str(ii)+' when invoking message reader');
  909.                             END;
  910.                           END ELSE
  911.                           BEGIN
  912. {$IFDEF MSGOBJECT}
  913.                             PoPEdMain;
  914. {$ENDIF}
  915.                           END;
  916.                    AltF : DisplayKeys(False);
  917. {                  AltG : SystemInfo;        See KEYBOARD.PAS }
  918. {                  AltH : ??}
  919.                    AltI : ExpandOutboundEntry;
  920. {                  AltJ : JumpToDOS;         See KEYBOARD.PAS }
  921. {                  AltK : KeyboardMacros;    See KEYBOARD.PAS }
  922.                    AltL : BEGIN
  923.                             mywin(TmpWin,19,11,60,13,2,'Lock Keyboard',True);
  924.                             Write(' Enter password,ESC=Abort,CR=Finished');
  925.                             Data.KbdPassword:='';
  926.                             REPEAT
  927.                               TmpCh:=Char(Lo(PopReadKeyWord));
  928.                               IF Not (TmpCh IN [#27,#13]) THEN Data.KbdPassword:=Data.KbdPassword+TmpCh;
  929.                             UNTIL TmpCh IN [#27,#13];
  930.                             KillWindow(TmpWin);
  931.                             IF (TmpCh<>#27) And (Data.KbdPassword<>'') THEN
  932.                             BEGIN
  933.                               TmpPassword:=''; KeyboardLock:=True;
  934.                               AddLog(' ','Keyboard locked');
  935.                             END ELSE
  936.                               Data.KbdPassword:='';
  937. {$IFNDEF OS2}
  938.                             WriteMacroStatus;
  939. {$ENDIF}
  940.                           END;
  941. {$IFNDEF NoMailScanner}
  942.                    AltM : RunMailScanner(0);
  943. {$ENDIF}
  944.                    AltN : BEGIN
  945.                             MakeModemBusy;
  946.                             NodeListManager;
  947.                           END;
  948.                    AltO : BEGIN
  949.                             MakeModemBusy;
  950.                             OutboundManager;
  951.                             NewTimerSecs(OutboundReRead, 1) ;
  952.                           END;
  953. {$IFNDEF Gamma}
  954.                    CtrlO: BEGIN
  955.                             MakeModemBusy;
  956.                             IF OutList^.Size>0 THEN
  957.                               Call:=CLOutListPtr^.Address
  958.                             ELSE
  959.                               FillChar(Call, SizeOf(Call), 0);
  960.                             NewOutboundManager(Call);
  961.                             NewTimerSecs(OutboundReRead, 1) ;
  962.                           END;
  963. {$ENDIF}
  964.                    AltP : IF CmdLineFlags AND clNoModem=0 THEN PollNode;
  965.                    AltQ : BEGIN
  966.                             MakeModemBusy;
  967.                             ListMain;
  968.                           END;
  969. {$IFDEF Repacker}
  970.                    AltR : BEGIN
  971.                             MakeModemBusy;
  972.                             RunRepacker;
  973.                           END;
  974. {$ENDIF}
  975.                    AltS : PortalStatus;
  976.                    AltT : IF SetInterCom(ICTextEdit,Call,True) THEN
  977.                           BEGIN
  978.                             MakeModemBusy;
  979.                             RunTextEditor('');
  980.                           END;
  981.                    AltU : IF (Cfg.BBS.BBSType<>btNone) And (SetInterCom(ICUserEd,Call,False)) THEN UserEditor;
  982.                    AltV : BEGIN
  983.                             MakeModemBusy;
  984.                             CompileNodeList(True);
  985.                           END;
  986.                    AltW : IF OutList^.Size>0 THEN
  987.                             DisplaySingleNode(CLOutListPtr^.Address);
  988.                    Esc,
  989.                    AltX : PortalFinished:=AskFinish;
  990.                    AltY : BEGIN
  991.                             MakeModemBusy;
  992.                             ScanNetMail;
  993.                             UpdateNetMailFlag;
  994.                           END;
  995.                    AltZ : BEGIN
  996.                             MakeModemBusy;
  997.                             ProcessTicks;
  998.                             ForwardFiles(Confirm('Add files to forward list','N',8));
  999.                             NewTimer(OutboundReRead, 0) ;
  1000.                           END;
  1001.                    F2   : BEGIN
  1002.                             LoadMainMenu;
  1003.                             MainMenu^.Draw;
  1004.                             InMainMenu:=True;
  1005.                             MainMenu^.Process;
  1006.                             InMainMenu:=False;
  1007.                             LastChoice:=MainMenu^.MenuChoice;
  1008. {$IFNDEF OS2}
  1009.                             IF LastChoice IN [90..97] THEN
  1010.                               MacroMenu(LastChoice)
  1011.                             ELSE
  1012. {$ENDIF}
  1013.                             BEGIN
  1014.                               IF (LastChoice<1) OR (LastChoice>40) THEN
  1015. {!!!  NOT (MainMenu^.MenuChoice IN [1..40]) THEN}
  1016.                                 MainMenu^.EraseAllSubMenus(True, True);
  1017.                               MainMenu^.Erase;
  1018.                             END;
  1019.                               IF (LastChoice>=1) AND (LastChoice<=40) THEN
  1020.                               BEGIN
  1021.                                 StuffKey(F10);
  1022.                                 Continue;
  1023.                               END ELSE
  1024.                               BEGIN
  1025.                                 CASE LastChoice OF
  1026.                                   200 : NewTimer(OutboundReRead, 0);
  1027.                                   210 : InitModemForEvent;
  1028.                                   211 : CheckModemResponse(True);
  1029.                                   212 : BEGIN
  1030.                                           MakeModemBusy;
  1031.                                           NewTimerSecs(ModemReInit, 60*60);
  1032.                                         END;
  1033.                                   213 : ShowAbout;
  1034.                                   214 : ExportConfig;
  1035.                                   215 : ImportConfig;
  1036. {$IFDEF MSGPACK}
  1037.                                   216 : PackMsg(false);
  1038. {$ENDIF}
  1039.                                   AltX: PortalFinished:=True;
  1040.                                   ELSE  StuffKey(LastChoice);
  1041.                                 END;
  1042.                                 LastChoice:=0;
  1043.                               END;
  1044.                           END;
  1045.                    F9   : AboutToday;
  1046.                    F10  : IF SetInterCom(ICConfig,Call,False) THEN
  1047.                           BEGIN
  1048.                             Configuration(False, LastChoice);
  1049.                             IF LastChoice=0 THEN
  1050.                             BEGIN
  1051.                               ChangeEvent(True);
  1052.                               UpdateStatusWindow;
  1053. {                             OutboundReRead:=TimerSet(100);}
  1054.                             END ELSE
  1055.                             BEGIN
  1056. {$IFNDEF OS2}
  1057.                               IF LastChoice IN [90..97] THEN MacroMenu(LastChoice);
  1058. {$ENDIF}
  1059.                               CASE LastChoice OF
  1060.                                 1..40 : StuffKey(F10);
  1061.                                 200 : NewTimer(OutboundReRead, 0);
  1062.                                 210 : InitModemForEvent;
  1063.                                 211 : CheckModemResponse(True);
  1064.                                 212 : BEGIN
  1065.                                         MakeModemBusy;
  1066.                                         NewTimerSecs(ModemReInit, 60*60);
  1067.                                       END;
  1068.                                 213 : ShowAbout;
  1069.                                 214 : ExportConfig;
  1070.                                 215 : ImportConfig;
  1071.                                 AltX: PortalFinished:=True;
  1072.                                 ELSE  StuffKey(LastChoice);
  1073.                               END;
  1074.                               IF NOT (LastChoice IN [1..40]) THEN LastChoice:=0 ELSE Continue;
  1075.                             END;
  1076.                           END;
  1077.                    Home : IF InLogWin THEN
  1078.                           BEGIN
  1079.                             IF CurrentLogView[1]>0 THEN
  1080.                             BEGIN
  1081.                               PortalLog.Seek(0);
  1082.                               i:=0;
  1083.                               REPEAT
  1084.                                 Inc(i);
  1085.                                 CurrentLogView[i]:=PortalLog.FilePos;
  1086.                                 PortalLog.ReadLine(s);
  1087.                               UNTIL i=LogLines+1;
  1088.                               ReWriteLogWindow;
  1089.                             END;
  1090.                           END ELSE
  1091.                           BEGIN
  1092.                             IF OutList^.Size>1 THEN
  1093.                             BEGIN
  1094.                               CLOutListPtr:=POutList(OutList^.Head);
  1095.                               FLOutListPtr:=CLOutListPtr;
  1096.                               UpdateOutboundWindow;
  1097.                             END;
  1098.                           END;
  1099.                    Up   : IF InLogWin THEN
  1100.                           BEGIN
  1101.                             IF CurrentLogView[1]>2 then
  1102.                             BEGIN
  1103.                               fp:=CurrentLogView[1];
  1104.                               Move(CurrentLogView[1],CurrentLogView[2],(LogLines)*4);
  1105.                               PortalLog.Seek(fp+2);
  1106.                               PortalLog.ReadLineBack(S);
  1107.                               CurrentLogView[1]:=PortalLog.FilePos-2;
  1108.                               WITH ActivityWindow^ DO
  1109.                               BEGIN
  1110.                                 ScrollVert(-1);
  1111.                                 WriteLogLine(S,1);
  1112. {$IFDEF UseScrollBars}
  1113.                                 DrawSlider(FrRR,CurrentLogView[1]);
  1114. {$ENDIF}
  1115.                               END;
  1116.                               JustScrolled:=True;
  1117.                             END;
  1118.                           END ELSE
  1119.                           BEGIN
  1120.                             IF (CLOutListPtr<>Nil) And (OutList^.Prev(CLOutListPtr)<>Nil) THEN
  1121.                             BEGIN
  1122.                               IF CLOutListPtr=FLOutListPtr THEN FLOutListPtr:=POutList(OutList^.Prev(FLOutListPtr));
  1123.                               CLOutListPtr:=POutList(OutList^.Prev(CLOutListPtr));
  1124.                               UpdateOutboundWindow;
  1125.                             END;
  1126.                           END;
  1127.                    PgUp : IF InLogWin THEN
  1128.                           BEGIN
  1129.                             IF CurrentLogView[1]>2 then
  1130.                             BEGIN
  1131.                               i:=LogLines-1;
  1132.                               REPEAT
  1133.                                 fp:=CurrentLogView[1];
  1134.                                 Move(CurrentLogView[1],CurrentLogView[2],(LogLines)*4);
  1135.                                 PortalLog.Seek(fp+2);
  1136.                                 PortalLog.ReadLineBack(S);
  1137.                                 CurrentLogView[1]:=PortalLog.FilePos-2;
  1138.                                 Dec(i);
  1139.                               Until (i=0) or (CurrentLogView[1]<2);
  1140.                               ReWriteLogWindow;
  1141.                               JustScrolled:=True;
  1142.                             END;
  1143.                           END ELSE
  1144.                           BEGIN
  1145.                             IF OutList^.Size>1 THEN
  1146.                             BEGIN
  1147.                               Tmp:=1;
  1148.                               WHILE (OutList^.Prev(CLOutListPtr)<>Nil) And (Tmp<4) DO
  1149.                               BEGIN
  1150.                                 Inc(Tmp);
  1151.                                 CLOutListPtr:=POutList(OutList^.Prev(CLOutListPtr));
  1152.                                 IF OutList^.Prev(FLOutListPtr)<>Nil THEN
  1153.                                   FLOutListPtr:=POutList(OutList^.Prev(FLOutListPtr));
  1154.                               END;
  1155.                               UpdateOutboundWindow;
  1156.                             END;
  1157.                           END;
  1158.                  EndKey : IF InlogWin THEN
  1159.                           BEGIN
  1160.                             IF EndLogView[1]<>CurrentLogView[1] THEN
  1161.                             BEGIN
  1162.                               CurrentLogView:=EndLogView;
  1163.                               ReWriteLogWindow;
  1164. {$IFDEF UseScrollBars}
  1165.                               ActivityWindow^.DrawSlider(FrRR,CurrentLogView[LogLines+1]);
  1166. {$ENDIF}
  1167.                             END;
  1168.                           END ELSE
  1169.                           IF OutList^.Size>1 THEN
  1170.                           BEGIN
  1171.                             CLOutListPtr:=POutList(OutList^.Tail);
  1172.                             FLOutListPtr:=CLOutListPtr; Tmp:=1;
  1173.                             WHILE (OutList^.Prev(FLOutListPtr)<>Nil) And (Tmp<4) DO
  1174.                             BEGIN
  1175.                               FLOutListPtr:=POutList(OutList^.Prev(FLOutListPtr));
  1176.                               Inc(Tmp);
  1177.                             END;
  1178.                             UpdateOutboundWindow;
  1179.                           END;
  1180.                    Down : If InLogWin then
  1181.                           BEGIN
  1182.                             FS:=PortalLog.FileSize;
  1183.                             IF CurrentLogView[Loglines+1]<FS-2 Then
  1184.                             BEGIN
  1185.                               Move(CurrentLogView[2],CurrentLogView[1],(LogLines)*4);
  1186.                               PortalLog.Seek(CurrentLogView[LogLines]);
  1187.                               PortalLog.ReadLine(s);
  1188.                               CurrentLogView[LogLines+1]:=CurrentLogView[LogLines]+Length(s)+2;
  1189.                               WITH ActivityWindow^ DO
  1190.                               BEGIN
  1191.                                 ScrollVert(1);
  1192.                                 WriteLogLine(s,LogLines);
  1193. {$IFDEF UseScrollBars}
  1194.                                 DrawSlider(FrRR,CurrentLogView[LogLines+1]);
  1195. {$ENDIF}
  1196.                               END;
  1197.                               JustScrolled:=True;
  1198.                             END;
  1199.                           END ELSE
  1200.                           BEGIN
  1201.                             IF (CLOutListPtr<>Nil) And (OutList^.Next(CLOutListPtr)<>Nil) THEN
  1202.                             BEGIN
  1203.                               CLOutListPtr:=POutList(OutList^.Next(CLOutListPtr));
  1204.                               SaveOutPtr:=FLOutListPtr; Tmp:=1;
  1205.                               WHILE (SaveOutPtr<>CLOutListPtr) And (Tmp<>5) DO
  1206.                               BEGIN
  1207.                                 Inc(Tmp);
  1208.                                 SaveOutPtr:=POutList(OutList^.Next(SaveOutPtr));
  1209.                               END;
  1210.                               IF Tmp=5 THEN FLOutListPtr:=POutList(OutList^.Next(FLOutListPtr));
  1211.                               UpdateOutboundWindow;
  1212.                             END;
  1213.                           END;
  1214.                    PgDn : IF InLogWin THEN
  1215.                           BEGIN
  1216.                             FS:=PortalLog.FileSize;
  1217.                             IF CurrentLogView[LogLines+1]<FS-2 then
  1218.                             BEGIN
  1219.                               i:=LogLines-1;
  1220.                               REPEAT
  1221.                                 Move(CurrentLogView[2],CurrentLogView[1],(LogLines)*4);
  1222.                                 PortalLog.Seek(CurrentLogView[LogLines]);
  1223.                                 PortalLog.ReadLine(S);
  1224.                                 CurrentLogView[LogLines+1]:=CurrentLogView[LogLines]+Length(s)+2;
  1225.                                 Dec(i);
  1226.                               Until (i=0) or (CurrentLogView[LogLines+1]>FS-4);
  1227.                               ReWriteLogWindow;
  1228.                               JustScrolled:=True;
  1229.                             END;
  1230.                           END ELSE
  1231.                           BEGIN
  1232.                             IF OutList^.Size>1 THEN
  1233.                             BEGIN
  1234.                               Tmp:=1;
  1235.                               WHILE (OutList^.Next(CLOutListPtr)<>Nil) And (Tmp<4) DO
  1236.                               BEGIN
  1237.                                 Inc(Tmp);
  1238.                                 CLOutListPtr:=POutList(OutList^.Next(CLOutListPtr));
  1239.                                 FLOutListPtr:=POutList(OutList^.Next(FLOutListPtr));
  1240.                               END;
  1241.                               UpdateOutboundWindow;
  1242.                             END;
  1243.                           END;
  1244.                    CtrlF1..CtrlF10 :
  1245.                           IF cfg.fkey[1,Hi(InKey)-93].errorlevel<>0 THEN
  1246.                           BEGIN
  1247.                             ComPort^.SetDtr(Low);
  1248.                             WITH cfg.fkey[1,Hi(InKey)-93] DO
  1249.                               SpawnWithErrorlevel(ErrorLevel, 'Function key exit "'+description+'"', True);
  1250.                           END;
  1251.                    AltF1..AltF10 :
  1252.                           IF cfg.fkey[2,Hi(InKey)-103].errorlevel<>0 THEN
  1253.                           BEGIN
  1254.                             ComPort^.SetDtr(Low);
  1255.                             WITH cfg.fkey[2,Hi(InKey)-103] DO
  1256.                               SpawnWithErrorlevel(ErrorLevel,'Function key exit "'+description+'"', True);
  1257.                           END;
  1258.                    Tab  : BEGIN
  1259.                             InLogWin:=Not InLogWin;
  1260.                             UpdateFrames;
  1261.                             NewTimerSecs(ReturnFromLog, 30);
  1262.                           END;
  1263.                    ELSE   ResetTimers:=False;
  1264.                  END;             {case ch2 of}
  1265.                END;               { #0 }
  1266.         END;                      {case ch of}
  1267.         IF Cfg.Modem.Answer<>'' THEN
  1268.         BEGIN
  1269.           IF NOT ComPort^.Carrier AND ComPort^.KeyPressed THEN
  1270.           BEGIN
  1271.             ComPort^.PurgeIn;
  1272.             NewTimerSecs(ModemReInit, 10);
  1273.           END;
  1274.         END;
  1275.         StartClock;
  1276.         SetInterCom(ICIdle,Call,False);
  1277.         IF ResetTimers THEN
  1278.         BEGIN
  1279.           NewTimerSecs(ScreenBlank, cfg.Screen.BlankTime);
  1280.           IF TimerExpired(Data.NextTime) THEN NewTimerSecs(Data.NextTime, 15);
  1281.         END;
  1282.       END ELSE
  1283.         GiveUpTime;
  1284.       IF NOT PortalFinished THEN
  1285.       BEGIN
  1286.         IF JustScrolled THEN
  1287.         BEGIN
  1288.           NewTimerSecs(ReturnFromLog, 30);
  1289.           IF Not ComPort^.Keypressed THEN Continue;
  1290.         END;
  1291.         CheckModemResponse(False);
  1292.         IF (InLogWin) And (TimerExpired(ReturnFromLog) Or
  1293.            ((Cfg.Screen.BlankTime<>0) AND TimerExpired(ScreenBlank))) THEN
  1294.         BEGIN
  1295.           InLogWin:=False;
  1296.           UpdateFrames;
  1297.         END;
  1298.         IF TimerExpired(ScreenBlank) And (Cfg.Screen.BlankTime>0) THEN TurnScreen(Off);
  1299.         IF (Cfg.Modem.ReInit<>0) AND (TimerExpired(ModemReInit)) THEN
  1300.           InitModemForEvent;
  1301.         IF ((Cfg.RereadOnCall) AND (TimerExpired(Data.NextTime)) AND
  1302.            NOT (MailToSend) AND ((CurrentEvent.Typ AND etReceive)=0)) OR
  1303.            (TimerExpired(OutboundReRead)) THEN
  1304.         BEGIN
  1305.           GetOutboundInformation;
  1306.           UpdateOutboundWindow;
  1307.           CheckSemaforeFiles;
  1308.         END;
  1309.         ChangeEvent(False);
  1310.         IF TimerExpired(Data.NextTime) THEN
  1311.         BEGIN
  1312.           IF (CmdLineFlags AND clNoModem=0) AND (OutList^.Size>0)  THEN
  1313.           BEGIN
  1314.             OldOutPtr:=CLOutListPtr;
  1315.             CLOutListPtr:=POutList(OutList^.Head);
  1316.             IF Data.LastCalled.Zone>0 THEN
  1317.             BEGIN
  1318.               WHILE (CLOutListPtr<>Nil) And
  1319.                     (Address2Sort(CLOutListPtr^.Address)<Address2Sort(Data.LastCalled)) DO
  1320.                 CLOutListPtr:=POutList(OutList^.Next(CLOutListPtr));
  1321.               IF CLOutListPtr=Nil THEN CLOutListPtr:=POutList(OutList^.Head);
  1322.             END;
  1323.             SaveOutPtr:=CLOutListPtr;
  1324.             MustReRead:=False;
  1325.             FillChar(Call, SizeOf(Call), 0);
  1326.             REPEAT
  1327.               IF OutList^.Next(CLOutListPtr)<>NIL THEN
  1328.                 CLOutListPtr:=POutList(OutList^.Next(CLOutListPtr))
  1329.               ELSE
  1330.                 CLOutListPtr:=POutList(OutList^.Head);
  1331.               IF CLOutListPtr^.Known AND SendableData(CLOutListPtr) THEN
  1332.                 Call:=ClOutListPtr^.Address;
  1333.               IF (Call.Net<>0) AND NOT StillHaveMail(Call) THEN
  1334.               BEGIN
  1335.                 Call.Net:=0;
  1336.                 MustReRead:=True;
  1337.               END;
  1338.             UNTIL (CLOutListPtr=SaveOutPtr) OR (Call.Net<>0);
  1339.             IF Call.Net<>0 THEN
  1340.             BEGIN
  1341.               Data.LastCalled:=Call;
  1342.               FLOutListPtr:=CLOutListPtr;
  1343.               UpdateOutboundWindow;
  1344.               Dial(False);
  1345.             END ELSE
  1346.               CLOutListPtr:=OldOutPtr;
  1347.             IF MustReRead THEN
  1348.             BEGIN
  1349.               NewTimer(OutboundReRead, 0);
  1350.               AddLog(' ','Mail seems to have been sent without my knowledge - forcing rescan!');
  1351.             END;
  1352.           END;
  1353.           NewTimerSecs(Data.NextTime, CalculateNextTime);
  1354.         END;
  1355.         IF TimerExpired(SemaforeTimer) THEN CheckSemaforeFiles;
  1356.       END;
  1357.     UNTIL PortalFinished;
  1358.     SetInterCom(ICUnused,Call,False);
  1359. {$IFDEF StackCheck}
  1360.     LogStackUsage;
  1361. {$ENDIF}
  1362.     AddLog('+','End, Portal of Power v'+Ver);
  1363.     ComPort^.SetDtr(Low);
  1364.     Dispose(ComPort, Done);
  1365.   END;
  1366.  
  1367. END.
  1368.